/*
 * Copyright 2008 Lucas Tan.
 * This copyright notice must always remain intact whenever you use or distribute 
 * the source code contained in this file.
 * Any usage of any code in this file, either in derived work or
 * through the use of external linkage,
 * must always be credited with the author's name.
 * 
 * 
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES 
 * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 
 * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 
 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 
 * DEALINGS IN THE SOFTWARE.
 * 
 * */
using System;
using System.Collections.Generic;
using System.Text;
using System.Xml;

namespace PassKeeper.Data
{
	public static class ParserUtil
	{
		public static int ParsePositiveInteger(XmlElement elem, string attributeName)
		{
			if (elem == null)
			{
				throw new ArgumentNullException("elem");
			}

			if (string.IsNullOrEmpty(attributeName))
			{
				throw new ArgumentException("Cannot be null or empty.", "attributeName");
			}

			string intStr = elem.GetAttribute(attributeName);
			if (string.IsNullOrEmpty(intStr))
			{
				throw new MissingAttributeException(elem.Name, attributeName);
			}

			int val = -1;

			try
			{
				/*Don't allow a sign since we assume it to be positive.
				 Don't allow whitespaces as well since the XML Document can't be modified
				 * after we have saved it without whitespaces.
				 */
				val = int.Parse(intStr, System.Globalization.NumberStyles.None);
			}
			catch (Exception e)
			{
				throw new AttributeParseException(elem.Name, attributeName, "Cannot parse positive integer.", e);
			}

			if (val <= 0)
			{
				throw new AttributeParseException(elem.Name, attributeName, "Not positive.");
			}

			return val;
		}

		public static void Dispose(object obj)
		{
			if (obj != null)
			{
				IDisposable disp = obj as IDisposable;

				if (disp != null)
				{
					disp.Dispose();
				}
			}
		}

		public static void Clear(byte[] array)
		{
			if (array == null)
			{
				throw new ArgumentNullException("array");
			}

			Array.Clear(array, 0, array.Length);
		}

		/// <summary>
		/// Retrieves a list of direct child elements with a specified tag name.
		/// </summary>
		/// <param name="elem">Parent element.</param>
		/// <param name="tagName">Tag name to look for.</param>
		/// <returns>A list of direct child elements with the specified tag name.</returns>
		/// <exception cref="ArgumentNullException"><paramref name="elem"/> is null.</exception>
		/// <exception cref="ArgumentException"><paramref name="tagName"/> is null or empty.</exception>
		public static XmlNodeList GetChildren(XmlElement elem, string tagName)
		{
			if (elem == null)
			{
				throw new ArgumentNullException("elem");
			}

			if (string.IsNullOrEmpty(tagName))
			{
				throw new ArgumentException("Cannot be null or empty.", "tagName");
			}

			return elem.SelectNodes( tagName );
		}

		/// <summary>
		/// Retrieves a single direct child element with a specified tag name.
		/// </summary>
		/// <param name="elem">Parent element.</param>
		/// <param name="tagName">Tag name of the child element to look for.</param>
		/// <returns>Direct child element with the specified tag name.</returns>
		/// <exception cref="ArgumentNullException"><paramref name="elem"/> is null.</exception>
		/// <exception cref="ArgumentException"><paramref name="tagName"/> is null or empty.</exception>
		/// <exception cref="MissingElementException">No child element with the specified tag name can be found.</exception>
		/// <exception cref="MultipleElementException">Multiple children with the specified tag name exist.</exception>
		public static XmlElement GetSingleChild(XmlElement elem, string tagName)
		{
			if (elem == null)
			{
				throw new ArgumentNullException("elem");
			}

			if (string.IsNullOrEmpty(tagName))
			{
				throw new ArgumentException("Cannot be null or empty.", "tagName");
			}

			XmlNodeList nodeList = GetChildren(elem, tagName);
			if (nodeList.Count == 1)
			{
				return (XmlElement) nodeList[0];
			}
			else if (nodeList.Count == 0)
			{
				throw new MissingElementException(tagName);
			}
			else
			{
				throw new MultipleElementException(tagName);
			}
		}
	}
}
